home *** CD-ROM | disk | FTP | other *** search
- #define LIBQBUILD_CORE
- #include "../include/libqbuild.h"
-
- vec3_t *texreflectivity;
- vec3_t *radiosity;
- vec3_t *illumination;
- struct patch **facepatches;
- struct entity **faceentity;
- struct patch *patches;
- int numpatches = 0;
- struct dplane_t *backplanes;
- int fakeplanes;
- int *leafparents;
- int *nodeparents;
- float subdiv = 64;
- struct directlight **directlights;
- struct facelight *facelights;
- int numdlights = 0;
- int numbounce = 8;
- bool dumppatches;
- int junk;
- float ambient = 0;
- float maxlight = 196;
- float lightscale = 1.0;
- float direct_scale = 0.4;
- float entity_scale = 1.0;
-
- extern struct tnode *tnodes, *tnode_p;
- int TestLine_r(register int node, vec3_t start, vec3_t stop)
- {
- struct tnode *tnode;
- float front, back;
- vec3_t mid;
- float frac;
- int side;
- int r;
-
- if (node & (1 << 31))
- return node & ~(1 << 31); // leaf node
-
- tnode = &tnodes[node];
- switch (tnode->type) {
- case PLANE_X:
- front = start[0] - tnode->dist;
- back = stop[0] - tnode->dist;
- break;
- case PLANE_Y:
- front = start[1] - tnode->dist;
- back = stop[1] - tnode->dist;
- break;
- case PLANE_Z:
- front = start[2] - tnode->dist;
- back = stop[2] - tnode->dist;
- break;
- default:
- front = DotProduct(start, tnode->normal) - tnode->dist;
- back = DotProduct(stop, tnode->normal) - tnode->dist;
- //
- // front = (start[0] * tnode->normal[0] + start[1] * tnode->normal[1] + start[2] * tnode->normal[2]) - tnode->dist;
- // back = (stop[0] * tnode->normal[0] + stop[1] * tnode->normal[1] + stop[2] * tnode->normal[2]) - tnode->dist;
- //
- break;
- }
-
- if (front >= -ON_EPSILON && back >= -ON_EPSILON)
- return TestLine_r(tnode->children[0], start, stop);
-
- if (front < ON_EPSILON && back < ON_EPSILON)
- return TestLine_r(tnode->children[1], start, stop);
-
- side = front < 0;
-
- frac = front / (front - back);
-
- mid[0] = start[0] + (stop[0] - start[0]) * frac;
- mid[1] = start[1] + (stop[1] - start[1]) * frac;
- mid[2] = start[2] + (stop[2] - start[2]) * frac;
-
- if((r = TestLine_r(tnode->children[side], start, mid)))
- return r;
- else
- return TestLine_r(tnode->children[!side], mid, stop);
- }
-
- /*
- * =============
- * CollectLight
- * =============
- */
- float CollectLight(void)
- {
- int i, j;
- struct patch *patch;
- vec_t total;
-
- total = 0;
-
- for (i = 0, patch = patches; i < numpatches; i++, patch++) {
- // skys never collect light, it is just dropped
- if (patch->sky) {
- VectorClear(radiosity[i]);
- VectorClear(illumination[i]);
- continue;
- }
-
- for (j = 0; j < 3; j++) {
- patch->totallight[j] += illumination[i][j] / patch->area;
- radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
- }
-
- total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
- VectorClear(illumination[i]);
- }
-
- return total;
- }
-
- /*
- * =============
- * ShootLight
- *
- * Send light out to other patches
- * Run multi-threaded
- * =============
- */
- void ShootLight(register int patchnum)
- {
- int k, l;
- struct transfer *trans;
- int num;
- struct patch *patch;
- vec3_t send;
-
- // this is the amount of light we are distributing
- // prescale it so that multiplying by the 16 bit
- // transfer values gives a proper output value
- for (k = 0; k < 3; k++)
- send[k] = radiosity[patchnum][k] / 0x10000;
- patch = &patches[patchnum];
-
- trans = patch->transfers;
- num = patch->numtransfers;
-
- for (k = 0; k < num; k++, trans++) {
- for (l = 0; l < 3; l++)
- illumination[trans->patch][l] += send[l] * trans->transfer;
- }
- }
-
- /*
- * =============
- * BounceLight
- * =============
- */
- void BounceLight(void)
- {
- int i, j;
- float added;
- struct patch *p;
-
- for (i = 0; i < numpatches; i++) {
- p = &patches[i];
- for (j = 0; j < 3; j++) {
- // p->totallight[j] = p->samplelight[j];
- radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
- }
- }
-
- for (i = 0; i < numbounce; i++) {
- for (j = 0; j < numpatches; j++)
- ShootLight(j);
-
- added = CollectLight();
- mprintf(" - bounce %i\n%5i added\n", i, added);
- }
- }
-
- void ClearLBounds (vec3_t mins, vec3_t maxs)
- {
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
- }
-
- void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
- {
- int i;
- vec_t val;
-
- for (i=0 ; i<3 ; i++) {
- val = v[i];
- if (val < mins[i])
- mins[i] = val;
- if (val > maxs[i])
- maxs[i] = val;
- }
- }
-
- /*
- * ===================================================================
- *
- * TEXTURE LIGHT VALUES
- *
- * ===================================================================
- */
-
- vec_t ColorNormalize (vec3_t in, vec3_t out)
- {
- float max;
-
- max = in[0];
- if (in[1] > max) max = in[1];
- if (in[2] > max) max = in[2];
-
- if (max != 0)
- VectorScale (in, 1.0 / max, out);
-
- return max;
- }
-
- /*
- * ======================
- * CalcTextureReflectivity
- * ======================
- */
- void CalcTextureReflectivity(__memBase)
- {
- int i, j;
- struct rgb *palette;
- struct dmiptexlump_t *l = (struct dmiptexlump_t *)bspMem->dtexdata;
-
- if(!(palette = GetPalette()))
- Error("CalcTextureRefletivity: failed to load palette\n");
-
- // allways set index 0 even if no textures
- texreflectivity[0][0] = 0.5;
- texreflectivity[0][1] = 0.5;
- texreflectivity[0][2] = 0.5;
-
- for (i = 0; i < bspMem->numtexinfo; i++) {
- struct texinfo *curtex = &bspMem->texinfo[i];
-
- // see if an earlier texinfo allready got the value
- for (j = 0; j < i; j++) {
- if (curtex->miptex == bspMem->texinfo[j].miptex) {
- VectorCopy(texreflectivity[j], texreflectivity[i]);
- break;
- }
- }
-
- if (j == i) {
- struct mipmap *mt = (struct mipmap *)(l->dataofs[curtex->miptex] + (int)l);
- int texels = mt->width * mt->height;
- unsigned char texel;
- unsigned char *body = (unsigned char *)mt + mt->offsets[MIPMAP_0];
- int color[3] = {0, 0, 0};
- float scale;
-
- for (j = 0; j < texels; j++) {
- texel = *body++;
- color[0] += palette[texel].r;
- color[1] += palette[texel].g;
- color[2] += palette[texel].b;
- }
-
- for (j = 0; j < 3; j++) {
- float r = color[j] / texels / 255.0;
- texreflectivity[i][j] = r;
- }
-
- mprintf("%s has a reflectivity of (%f,%f,%f)\n", mt->name, texreflectivity[i][0], texreflectivity[i][1], texreflectivity[i][2]);
-
- // scale the reflectivity up, because the textures are
- // so dim
- scale = ColorNormalize(texreflectivity[i], texreflectivity[i]);
- if (scale < 0.5) {
- scale *= 2;
- VectorScale(texreflectivity[i], scale, texreflectivity[i]);
- }
- }
- }
- }
-
- /*
- * ===================
- * DecompressVis
- * ===================
- */
- void DecompressVis(__memBase, register unsigned char *in, register unsigned char *decompressed)
- {
- int c;
- int row;
- unsigned char *out;
-
- row = (bspMem->numleafs + 7) >> 3;
- out = decompressed;
-
- do {
- if (*in) {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- in += 2;
- while (c) {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
- }
-
- int PointInLeafNum(__memBase, vec3_t point)
- {
- int nodenum;
- vec_t dist;
- struct dnode_t *node;
- struct dplane_t *plane;
-
- nodenum = 0;
- while (nodenum >= 0) {
- node = &bspMem->dnodes[nodenum];
- plane = &bspMem->dplanes[node->planenum];
- dist = DotProduct(point, plane->normal) - plane->dist;
- if (dist > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
-
- return -nodenum - 1;
- }
-
- bool PvsForOrigin(__memBase, vec3_t org, register unsigned char *pvs)
- {
- if (!bspMem->visdatasize) {
- memset(pvs, 255, (bspMem->numleafs + 7) >> 3);
- }
- else {
- struct dleaf_t *leaf = &bspMem->dleafs[PointInLeafNum(bspMem, org)];
- DecompressVis(bspMem, bspMem->dvisdata + leaf->visofs, pvs);
- }
-
- return TRUE;
- }
-
- /*
- * =============
- * MakeBackplanes
- * =============
- */
- void MakeBackPlanes(__memBase)
- {
- int i;
-
- for (i = 0; i < bspMem->numplanes; i++) {
- backplanes[i].dist = -bspMem->dplanes[i].dist;
- VectorNegateTo(bspMem->dplanes[i].normal, backplanes[i].normal);
- }
- }
-
- /*
- * =============
- * MakeParents
- * =============
- */
- void MakeParents(__memBase, register int nodenum, register int parent)
- {
- int i, j;
- struct dnode_t *node;
-
- nodeparents[nodenum] = parent;
- node = &bspMem->dnodes[nodenum];
-
- for (i = 0; i < 2; i++) {
- j = node->children[i];
- if (j < 0)
- leafparents[-j - 1] = nodenum;
- else
- MakeParents(bspMem, j, nodenum);
- }
- }
-
- /*
- * =============
- * MakePatchForFace
- * =============
- */
-
- bool IsSky(__memBase, register struct dface_t * f)
- {
- struct texinfo *tx;
- struct mipmap *mt;
- struct dmiptexlump_t *l = (struct dmiptexlump_t *)bspMem->dtexdata;
-
- tx = &bspMem->texinfo[f->texinfo];
- mt = (struct mipmap *)(l->dataofs[tx->miptex] + (int)l);
- if(!strcmp(mt->name, "sky"))
- return TRUE;
- return FALSE;
- }
-
- #define MAX_PATCHES 4096
- float totalarea;
- void MakePatchForFace(__memBase, register int facenum, register struct winding *w)
- {
- struct dface_t *f;
- float area;
- struct patch *patch;
- struct dplane_t *pl;
- int i;
- vec3_t color;
- struct dleaf_t *leaf;
-
- f = &bspMem->dfaces[facenum];
-
- area = WindingArea(w);
- totalarea += area;
-
- patch = &patches[numpatches];
- if (numpatches == MAX_PATCHES)
- Error("numpatches == MAX_PATCHES\n");
- patch->next = facepatches[facenum];
- facepatches[facenum] = patch;
-
- patch->winding = w;
-
- if (f->side)
- patch->plane = &backplanes[f->planenum];
- else
- patch->plane = &bspMem->dplanes[f->planenum];
- if (faceoffset[facenum][0] || faceoffset[facenum][1] || faceoffset[facenum][2]) { // origin offset faces must create new planes
- if(bspMem->numplanes + fakeplanes >= bspMem->max_numplanes)
- ExpandClusters(bspMem, LUMP_PLANES);
- pl = &bspMem->dplanes[bspMem->numplanes + fakeplanes];
- fakeplanes++;
-
- *pl = *(patch->plane);
- pl->dist += DotProduct(faceoffset[facenum], pl->normal);
- patch->plane = pl;
- }
-
- WindingCenter(w, patch->origin);
- VectorAdd(patch->origin, patch->plane->normal, patch->origin);
- leaf = &bspMem->dleafs[PointInLeafNum(bspMem, patch->origin)];
- patch->cluster = leaf->visofs;
- patch->area = area;
- if (patch->area <= 1)
- patch->area = 1;
- patch->sky = IsSky(bspMem, f);
-
- VectorCopy(texreflectivity[f->texinfo], patch->reflectivity);
-
- // non-bmodel patches can emit light
- if (facenum < bspMem->dmodels[0].numfaces) {
- VectorClear(patch->baselight);
- ColorNormalize(patch->reflectivity, color);
- for (i = 0; i < 3; i++)
- patch->baselight[i] *= color[i];
- VectorCopy(patch->baselight, patch->totallight);
- }
- numpatches++;
- }
-
- /*
- * =============
- * MakePatches
- * =============
- */
- void MakePatches(__memBase)
- {
- int i, j, k;
- struct dface_t *f;
- int start;
- struct winding *w;
- struct dmodel_t *mod;
- struct entity *ent;
-
- mprintf("%5i faces\n", bspMem->numfaces);
-
- for (i = 0; i < bspMem->nummodels; i++) {
- mod = &bspMem->dmodels[i];
- ent = FindEntityWithModel(bspMem, i);
- // bmodels with origin brushes need to be offset into their
- // in-use position
- start = mod->firstface;
- for (j = start; j < start + mod->numfaces; j++) {
- VectorCopy(ent->origin, faceoffset[j]);
- faceentity[j] = ent;
- f = &bspMem->dfaces[j];
- w = WindingFromFace(bspMem, f);
- for (k = 0; k < w->numpoints; k++) {
- VectorAdd(w->points[k], ent->origin, w->points[k]);
- }
- MakePatchForFace(bspMem, j, w);
- }
- }
-
- mprintf("%5i square feet\n", (int)(totalarea / 64));
- }
-
- void CheckPatches(void)
- {
- int i;
- struct patch *patch;
-
- for (i = 0; i < numpatches; i++) {
- patch = &patches[i];
- if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
- Error("negative patch totallight\n");
- }
- }
-
- /*
- * =============
- * MakeTransfers
- *
- * =============
- */
- int total_transfer;
-
- void MakeTransfers(__memBase, register int i)
- {
- int j;
- vec3_t delta;
- vec_t dist, scale;
- float trans;
- int itrans;
- struct patch *patch, *patch2;
- float total;
- struct dplane_t plane;
- vec3_t origin;
- float transfers[MAX_PATCHES], *all_transfers;
- int itotal;
- unsigned char pvs[(MAX_MAP_LEAFS + 7) / 8];
- int cluster;
-
- patch = patches + i;
- total = 0;
-
- VectorCopy(patch->origin, origin);
- plane = *patch->plane;
-
- if (!PvsForOrigin(bspMem, patch->origin, pvs))
- return;
-
- // find out which patch2s will collect light
- // from patch
-
- all_transfers = transfers;
- patch->numtransfers = 0;
- for (j = 0, patch2 = patches; j < numpatches; j++, patch2++) {
- transfers[j] = 0;
-
- if (j == i)
- continue;
-
- // check pvs bit
- if (!bspMem->visdatasize) {
- cluster = patch2->cluster;
- if (cluster == -1)
- continue;
- if (!(pvs[cluster >> 3] & (1 << (cluster & 7))))
- continue; // not in pvs
- }
-
- // calculate vector
- VectorSubtract(patch2->origin, origin, delta);
- dist = VectorNormalize(delta);
- if (!dist)
- continue; // should never happen
-
- // reletive angles
- scale = DotProduct(delta, plane.normal);
- scale *= -DotProduct(delta, patch2->plane->normal);
- if (scale <= 0)
- continue;
-
- // check exact tramsfer
- if (TestLine_r(0, patch->origin, patch2->origin))
- continue;
-
- trans = scale * patch2->area / (dist * dist);
-
- if (trans < 0)
- trans = 0; // rounding errors...
-
- transfers[j] = trans;
- if (trans > 0) {
- total += trans;
- patch->numtransfers++;
- }
- }
-
- // copy the transfers out and normalize
- // total should be somewhere near PI if everything went right
- // because partial occlusion isn't accounted for, and nearby
- // patches have underestimated form factors, it will usually
- // be higher than PI
- if (patch->numtransfers) {
- struct transfer *t;
-
- if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
- Error("Weird numtransfers\n");
- if(!(patch->transfers = (struct transfer *)tmalloc(patch->numtransfers * sizeof(struct transfer))))
- Error("MakeTransfers: failed to allocate transfer!\n");
-
- //
- // normalize all transfers so all of the light
- // is transfered to the surroundings
- //
- t = patch->transfers;
- itotal = 0;
- for (j = 0; j < numpatches; j++) {
- if (transfers[j] <= 0)
- continue;
- itrans = transfers[j] * 0x10000 / total;
- itotal += itrans;
- t->transfer = itrans;
- t->patch = j;
- t++;
- }
- }
-
- // don't bother locking around this. not that important.
- total_transfer += patch->numtransfers;
- }
-
- /*
- * =============
- * FreeTransfers
- * =============
- */
- void FreeTransfers(void)
- {
- int i;
-
- for (i = 0; i < numpatches; i++) {
- tfree(patches[i].transfers);
- patches[i].transfers = NULL;
- }
- }
-
- /*
- * =======================================================================
- *
- * SUBDIVIDE
- *
- * =======================================================================
- */
-
- void FinishSplit(__memBase, register struct patch * patch, register struct patch * newp)
- {
- struct dleaf_t *leaf;
-
- VectorCopy(patch->baselight, newp->baselight);
- VectorCopy(patch->totallight, newp->totallight);
- VectorCopy(patch->reflectivity, newp->reflectivity);
- newp->plane = patch->plane;
- newp->sky = patch->sky;
-
- patch->area = WindingArea(patch->winding);
- newp->area = WindingArea(newp->winding);
-
- if (patch->area <= 1)
- patch->area = 1;
- if (newp->area <= 1)
- newp->area = 1;
-
- WindingCenter(patch->winding, patch->origin);
- VectorAdd(patch->origin, patch->plane->normal, patch->origin);
- leaf = &bspMem->dleafs[PointInLeafNum(bspMem, patch->origin)];
- patch->cluster = leaf->visofs;
-
- WindingCenter(newp->winding, newp->origin);
- VectorAdd(newp->origin, newp->plane->normal, newp->origin);
- leaf = &bspMem->dleafs[PointInLeafNum(bspMem, newp->origin)];
- newp->cluster = leaf->visofs;
- }
-
- /*
- * =============
- * SubdividePatch
- *
- * Chops the patch only if its local bounds exceed the max size
- * =============
- */
- void SubdividePatch(__memBase, register struct patch * patch)
- {
- struct winding *w, *o1, *o2;
- vec3_t mins, maxs, total;
- vec3_t split;
- vec_t dist;
- int i, j;
- vec_t v;
- struct patch *newp;
-
- w = patch->winding;
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
- for (i = 0; i < w->numpoints; i++) {
- for (j = 0; j < 3; j++) {
- v = w->points[i][j];
- if (v < mins[j]) mins[j] = v;
- if (v > maxs[j]) maxs[j] = v;
- }
- }
- VectorSubtract(maxs, mins, total);
- for (i = 0; i < 3; i++)
- if (total[i] > (subdiv + 1))
- // no splitting needed
- return;
-
- //
- // split the winding
- //
- VectorClear(split);
- split[i] = 1;
- dist = (mins[i] + maxs[i]) * 0.5;
- ClipWindingEpsilon(w, split, dist, ON_EPSILON, &o1, &o2);
-
- //
- // create a new patch
- //
- if (numpatches == MAX_PATCHES)
- Error("MAX_PATCHES\n");
- newp = &patches[numpatches];
- numpatches++;
-
- newp->next = patch->next;
- patch->next = newp;
-
- patch->winding = o1;
- newp->winding = o2;
-
- FinishSplit(bspMem, patch, newp);
-
- SubdividePatch(bspMem, patch);
- SubdividePatch(bspMem, newp);
- }
-
- /*
- * =============
- * DicePatch
- *
- * Chops the patch by a global grid
- * =============
- */
- void DicePatch(__memBase, register struct patch * patch)
- {
- struct winding *w, *o1, *o2;
- vec3_t mins, maxs;
- vec3_t split;
- vec_t dist;
- int i;
- struct patch *newp;
-
- w = patch->winding;
- WindingBounds(w, mins, maxs);
- for (i = 0; i < 3; i++)
- if (floor((mins[i] + 1) / subdiv) < floor((maxs[i] - 1) / subdiv))
- break;
- if (i == 3) {
- // no splitting needed
- return;
- }
-
- //
- // split the winding
- //
- VectorClear(split);
- split[i] = 1;
- dist = subdiv * (1 + floor((mins[i] + 1) / subdiv));
- ClipWindingEpsilon(w, split, dist, ON_EPSILON, &o1, &o2);
-
- //
- // create a new patch
- //
- if (numpatches == MAX_PATCHES)
- Error("MAX_PATCHES\n");
- newp = &patches[numpatches];
- numpatches++;
-
- newp->next = patch->next;
- patch->next = newp;
-
- patch->winding = o1;
- newp->winding = o2;
-
- FinishSplit(bspMem, patch, newp);
-
- DicePatch(bspMem, patch);
- DicePatch(bspMem, newp);
- }
-
- /*
- * =============
- * SubdividePatches
- * =============
- */
- void SubdividePatches(__memBase)
- {
- int i, num;
-
- if (subdiv < 1)
- return;
-
- num = numpatches; // because the list will grow
-
- for (i = 0; i < num; i++)
- // SubdividePatch (&patches[i]);
- DicePatch(bspMem, &patches[i]);
-
- mprintf("%5i patches after subdivision\n", numpatches);
- }
-
- /*
- * ================
- * CalcFaceExtents
- *
- * Fills in s->texmins[] and s->texsize[]
- * also sets exactmins[] and exactmaxs[]
- * ================
- */
- void CalcFaceExtentsII(__memBase, register struct lightinfo * l)
- {
- struct dface_t *s;
- vec_t mins[2], maxs[2], val;
- int i, j, e;
- struct dvertex_t *v;
- struct texinfo *tex;
- vec3_t vt;
-
- s = l->face;
-
- mins[0] = mins[1] = 999999;
- maxs[0] = maxs[1] = -99999;
-
- tex = &bspMem->texinfo[s->texinfo];
-
- for (i = 0; i < s->numedges; i++) {
- e = bspMem->dsurfedges[s->firstedge + i];
- if (e >= 0)
- v = bspMem->dvertexes + bspMem->dedges[e].v[0];
- else
- v = bspMem->dvertexes + bspMem->dedges[-e].v[1];
-
- // VectorAdd (v->point, l->modelorg, vt);
- VectorCopy(v->point, vt);
-
- for (j = 0; j < 2; j++) {
- val = DotProduct(vt, tex->vecs[j]) + tex->vecs[j][3];
- if (val < mins[j])
- mins[j] = val;
- if (val > maxs[j])
- maxs[j] = val;
- }
- }
-
- for (i = 0; i < 2; i++) {
- l->exactmins[i] = mins[i];
- l->exactmaxs[i] = maxs[i];
-
- mins[i] = floor(mins[i] / 16);
- maxs[i] = ceil(maxs[i] / 16);
-
- l->texmins[i] = mins[i];
- l->texsize[i] = maxs[i] - mins[i];
-
- if (l->texsize[0] * l->texsize[1] > SINGLEMAP / 4) // div 4 for extrasamples
- printf("Surface to large to map: %d*%d", l->texsize[0], l->texsize[1]);
- }
- }
-
- /*
- * =================================================================
- *
- * LIGHTMAP SAMPLE GENERATION
- *
- * =================================================================
- */
-
- #define ANGLE_UP -1
- #define ANGLE_DOWN -2
-
- /*
- * =============
- * CreateDirectLights
- * =============
- */
- void CreateDirectLights(__memBase)
- {
- int i;
- struct patch *p;
- struct directlight *dl;
- struct dleaf_t *leaf;
- int cluster;
- struct entity *e, *e2;
- float angle;
- char *_color;
- float intensity;
-
- //
- // surfaces
- //
- for (i = 0, p = patches; i < numpatches; i++, p++) {
- if (p->totallight[0] < DIRECT_LIGHT
- && p->totallight[1] < DIRECT_LIGHT
- && p->totallight[2] < DIRECT_LIGHT)
- continue;
-
- if(!(dl = (struct directlight *)tmalloc(sizeof(struct directlight))))
- Error("CreateDirectLights: failed to allocate directlight!\n");
- numdlights++;
-
- VectorCopy(p->origin, dl->origin);
-
- leaf = &bspMem->dleafs[PointInLeafNum(bspMem, dl->origin)];
- cluster = leaf->visofs;
- dl->next = directlights[cluster];
- directlights[cluster] = dl;
-
- dl->type = emit_surface;
- VectorCopy(p->plane->normal, dl->normal);
-
- dl->intensity = ColorNormalize(p->totallight, dl->color);
- dl->intensity *= p->area * direct_scale;
- VectorClear(p->totallight); // all sent now
- }
-
- //
- // entities
- //
- for (i = 0; i < bspMem->nummapentities; i++) {
- e = &bspMem->mapentities[i];
- if (strncmp(e->classname, "light", 5))
- continue;
-
- if(!(dl = (struct directlight *)tmalloc(sizeof(struct directlight))))
- Error("CreateDirectLights: failed to allocate directlight!\n");
- numdlights++;
-
- VectorCopy(e->origin, dl->origin);
- dl->style = e->style;
-
- leaf = &bspMem->dleafs[PointInLeafNum(bspMem, dl->origin)];
- cluster = leaf->visofs;
- dl->next = directlights[cluster];
- directlights[cluster] = dl;
-
- intensity = e->light;
- _color = ValueForKey(e, "_color");
- if (_color && _color[1]) {
- sscanf(_color, "%g %g %g", &dl->color[0], &dl->color[1], &dl->color[2]);
- ColorNormalize(dl->color, dl->color);
- }
- else
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
- dl->intensity = intensity * entity_scale;
- dl->type = emit_point;
-
- if (e->target || !strcmp(e->target, "light_spot")) {
- dl->type = emit_spotlight;
- dl->stopdot = FloatForKey(e, "_cone");
- if (!dl->stopdot)
- dl->stopdot = 10;
- dl->stopdot = cos(dl->stopdot / 180 * 3.14159);
- if (e->target[0]) { // point towards target
- if (!(e2 = e->targetent))
- eprintf("light at (%g %g %g) has missing target\n",
- dl->origin[0], dl->origin[1], dl->origin[2]);
- else {
- VectorSubtract(e2->origin, dl->origin, dl->normal);
- VectorNormalize(dl->normal);
- }
- }
- else { // point down angle
- angle = e->angle;
- if (angle == ANGLE_UP) {
- dl->normal[0] = dl->normal[1] = 0;
- dl->normal[2] = 1;
- }
- else if (angle == ANGLE_DOWN) {
- dl->normal[0] = dl->normal[1] = 0;
- dl->normal[2] = -1;
- }
- else {
- dl->normal[2] = 0;
- dl->normal[0] = cos(angle / 180 * 3.14159);
- dl->normal[1] = sin(angle / 180 * 3.14159);
- }
- }
- }
- }
-
- mprintf("%5i direct lights\n", numdlights);
- }
-
- /*
- * =============
- * AddSampleToPatch
- *
- * Take the sample's collected light and
- * add it back into the apropriate patch
- * for the radiosity pass.
- *
- * The sample is added to all patches that might include
- * any part of it. They are counted and averaged, so it
- * doesn't generate extra light.
- * =============
- */
- void AddSampleToPatch(vec3_t pos, vec3_t color, register int facenum)
- {
- struct patch *patch;
- vec3_t mins, maxs;
- int i;
-
- if (numbounce == 0)
- return;
- if (color[0] + color[1] + color[2] < 3)
- return;
-
- for (patch = facepatches[facenum]; patch; patch = patch->next) {
- // see if the point is in this patch (roughly)
- WindingBounds(patch->winding, mins, maxs);
- for (i = 0; i < 3; i++) {
- if (mins[i] > pos[i] + 16)
- goto nextpatch;
- if (maxs[i] < pos[i] - 16)
- goto nextpatch;
- }
-
- // add the sample to the patch
- patch->samples++;
- VectorAdd(patch->samplelight, color, patch->samplelight);
- nextpatch:;
- }
- }
-
- /*
- * =================================================================
- *
- * POINT TRIANGULATION
- *
- * =================================================================
- */
-
- struct edgeshare {
- struct dface_t *faces[2];
- bool coplanar;
- };
-
- int *facelinks; //[MAX_MAP_FACES];
- int *planelinks[2]; //[MAX_MAP_PLANES];
-
- /*
- * ============
- * LinkPlaneFaces
- * ============
- */
- void LinkPlaneFaces(__memBase)
- {
- int i;
- struct dface_t *f;
-
- if(!(facelinks = (int *)kmalloc(bspMem->numfaces * sizeof(int))))
- Error("LinkPlaneFaces: failed to allocate facelinks!\n");
- if(!(planelinks[0] = (int *)kmalloc(bspMem->numplanes * sizeof(int))))
- Error("LinkPlaneFaces: failed to allocate planelinks0!\n");
- if(!(planelinks[1] = (int *)kmalloc(bspMem->numplanes * sizeof(int))))
- Error("LinkPlaneFaces: failed to allocate planelinks1!\n");
-
- f = bspMem->dfaces;
- for (i = 0; i < bspMem->numfaces; i++, f++) {
- facelinks[i] = planelinks[f->side][f->planenum];
- planelinks[f->side][f->planenum] = i;
- }
- }
-
- /*
- * ============
- * PairEdges
- * ============
- */
- void PairEdges(__memBase)
- {
- int i, j, k;
- struct dface_t *f;
- struct edgeshare *e;
- struct edgeshare *edgeshare;
-
- if(!(edgeshare = (struct edgeshare *)tmalloc(bspMem->numedges * sizeof(struct edgeshare))))
- Error("PairEdges: failed to allocate edgeshare!\n");
-
- f = bspMem->dfaces;
- for (i = 0; i < bspMem->numfaces; i++, f++) {
- for (j = 0; j < f->numedges; j++) {
- k = bspMem->dsurfedges[f->firstedge + j];
- if (k < 0) {
- e = &edgeshare[-k];
- e->faces[1] = f;
- }
- else {
- e = &edgeshare[k];
- e->faces[0] = f;
- }
-
- if (e->faces[0] && e->faces[1]) {
- // determine if coplanar
- if (e->faces[0]->planenum == e->faces[1]->planenum)
- e->coplanar = TRUE;
- }
- }
- }
-
- tfree(edgeshare);
- }
-
- /*
- * ===============
- * AllocTriangulation
- * ===============
- */
- struct triangulation *AllocTriangulation(register struct dplane_t *plane) {
- struct triangulation *t ;
- if(!(t = (struct triangulation *)tmalloc(sizeof(struct triangulation))))
- Error("AllocTriangulation: failed to allocate triangulation!\n");
- t->plane = plane;
- return t;
- }
-
- /*
- * ===============
- * FreeTriangulation
- * ===============
- */
- void FreeTriangulation(register struct triangulation *trian) {
- if(trian->matrixsquare)
- tfree(trian->edgematrix);
- if(trian->numedges)
- tfree(trian->edges);
- if(trian->numpoints)
- tfree(trian->points);
- if(trian->numtris)
- tfree(trian->tris);
- tfree(trian);
- }
-
- struct triedge *FindTriEdge(register struct triangulation * trian, register int p0, register int p1)
- {
- struct triedge *e, *be;
- vec3_t v1;
- vec3_t normal;
- vec_t dist;
-
- // recalculation
- if((trian->matrixsquare < p0) || (trian->matrixsquare < p1)) {
- struct triedge **newtrie;
- int i, newsquare = p0 > p1 ? p0 : p1;
- unsigned char *new, *old;
-
- if(!(newtrie = (struct triedge **)tmalloc(newsquare * newsquare * sizeof(struct triedge *))))
- Error("FindTriEdge: failed to allocate triedges!\n");
-
- new = (unsigned char *)newtrie;
- old = (unsigned char *)trian->edgematrix;
-
- for(i = 0; i < trian->matrixsquare; i++) {
- memcpy(new + (i * newsquare), old + (i * trian->matrixsquare), trian->matrixsquare * sizeof(struct triedge *));
- }
-
- tfree(trian->edgematrix);
- trian->edgematrix = newtrie;
- trian->matrixsquare = newsquare;
- }
- else if (trian->edgematrix[(p0 * trian->matrixsquare) + p1])
- return trian->edgematrix[(p0 * trian->matrixsquare) + p1];
-
- if (trian->numedges > MAX_TRI_EDGES - 2)
- Error("trian->numedges > MAX_TRI_EDGES-2");
-
- VectorSubtract(trian->points[p1]->origin, trian->points[p0]->origin, v1);
- VectorNormalize(v1);
- CrossProduct(v1, trian->plane->normal, normal);
- dist = DotProduct(trian->points[p0]->origin, normal);
-
- if(!(trian->edges = (struct triedge *)trealloc(trian->edges, (trian->numedges + 2) * sizeof(struct triedge))))
- Error("FindTriEdge: failed to allocate triedges!\n");
-
- e = &trian->edges[trian->numedges];
- e->p0 = p0;
- e->p1 = p1;
- e->tri = NULL;
- VectorCopy(normal, e->normal);
- e->dist = dist;
- trian->numedges++;
- trian->edgematrix[(p0 * trian->matrixsquare) + p1] = e;
-
- be = &trian->edges[trian->numedges];
- be->p0 = p1;
- be->p1 = p0;
- be->tri = NULL;
- VectorNegateTo(normal, be->normal);
- be->dist = -dist;
- trian->numedges++;
- trian->edgematrix[(p1 * trian->matrixsquare) + p0] = be;
-
- return e;
- }
-
- struct triangle *AllocTriangle(register struct triangulation *trian) {
- if(!(trian->tris = (struct triangle *)trealloc(trian->tris, ++trian->numtris * sizeof(struct triangle))))
- Error("AllocTriangle: failed to allocate triangle!\n");
- return trian->tris + trian->numtris - 1;
- }
-
- /*
- * ============
- * TriEdge_r
- * ============
- */
- void TriEdge_r(register struct triangulation * trian, register struct triedge * e)
- {
- int i, bestp = 0;
- vec3_t v1, v2;
- vec_t *p0, *p1, *p;
- vec_t best, ang;
- struct triangle *nt;
-
- if (e->tri)
- return; // allready connected by someone
-
- // find the point with the best angle
- p0 = trian->points[e->p0]->origin;
- p1 = trian->points[e->p1]->origin;
- best = 1.1;
- for (i = 0; i < trian->numpoints; i++) {
- p = trian->points[i]->origin;
- // a 0 dist will form a degenerate triangle
- if (DotProduct(p, e->normal) - e->dist < 0)
- continue; // behind edge
-
- VectorSubtract(p0, p, v1);
- VectorSubtract(p1, p, v2);
- if (!VectorNormalize(v1))
- continue;
- if (!VectorNormalize(v2))
- continue;
- ang = DotProduct(v1, v2);
- if (ang < best) {
- best = ang;
- bestp = i;
- }
- }
- if (best >= 1)
- return; // edge doesn't match anything
-
- // make a new triangle
- nt = AllocTriangle(trian);
- nt->edges[0] = e;
- nt->edges[1] = FindTriEdge(trian, e->p1, bestp);
- nt->edges[2] = FindTriEdge(trian, bestp, e->p0);
- for (i = 0; i < 3; i++)
- nt->edges[i]->tri = nt;
- TriEdge_r(trian, FindTriEdge(trian, bestp, e->p1));
- TriEdge_r(trian, FindTriEdge(trian, e->p0, bestp));
- }
-
- /*
- * ============
- * TriangulatePoints
- * ============
- */
- void TriangulatePoints(register struct triangulation * trian)
- {
- vec_t d, bestd;
- vec3_t v1;
- int bp1 = 0, bp2 = 0, i, j;
- vec_t *p1, *p2;
- struct triedge *e, *e2;
-
- if (trian->numpoints < 2)
- return;
-
- // find the two closest points
- bestd = 9999;
- for (i = 0; i < trian->numpoints; i++) {
- p1 = trian->points[i]->origin;
- for (j = i + 1; j < trian->numpoints; j++) {
- p2 = trian->points[j]->origin;
- VectorSubtract(p2, p1, v1);
- d = VectorLength(v1);
- if (d < bestd) {
- bestd = d;
- bp1 = i;
- bp2 = j;
- }
- }
- }
-
- e = FindTriEdge(trian, bp1, bp2);
- e2 = FindTriEdge(trian, bp2, bp1);
- TriEdge_r(trian, e);
- TriEdge_r(trian, e2);
- }
-
- /*
- * ===============
- * AddPointToTriangulation
- * ===============
- */
- void AddPointToTriangulation(register struct patch *patch, register struct triangulation *trian) {
- if(!(trian->points = (struct patch **)trealloc(trian->points, ++trian->numpoints * sizeof(struct patch *))))
- Error("AddPointToTriangulation: failed to allocate point!\n");
- trian->points[trian->numpoints - 1] = patch;
- }
-
- /*
- * ===============
- * LerpTriangle
- * ===============
- */
- void LerpTriangle(register struct triangulation * trian, register struct triangle * t, vec3_t point, vec3_t color)
- {
- struct patch *p1, *p2, *p3;
- vec3_t base, d1, d2;
- float x, y, x1, y1, x2, y2;
-
- p1 = trian->points[t->edges[0]->p0];
- p2 = trian->points[t->edges[1]->p0];
- p3 = trian->points[t->edges[2]->p0];
-
- VectorCopy(p1->totallight, base);
- VectorSubtract(p2->totallight, base, d1);
- VectorSubtract(p3->totallight, base, d2);
-
- x = DotProduct(point, t->edges[0]->normal) - t->edges[0]->dist;
- y = DotProduct(point, t->edges[2]->normal) - t->edges[2]->dist;
-
- x1 = 0;
- y1 = DotProduct(p2->origin, t->edges[2]->normal) - t->edges[2]->dist;
-
- x2 = DotProduct(p3->origin, t->edges[0]->normal) - t->edges[0]->dist;
- y2 = 0;
-
- if (fabs(y1) < ON_EPSILON || fabs(x2) < ON_EPSILON) {
- VectorCopy(base, color);
- return;
- }
-
- VectorMA(base, x / x2, d2, color);
- VectorMA(color, y / y1, d1, color);
- }
-
- bool PointInTriangle(vec3_t point, register struct triangle * t)
- {
- int i;
- struct triedge *e;
- vec_t d;
-
- for (i = 0; i < 3; i++) {
- e = t->edges[i];
- d = DotProduct(e->normal, point) - e->dist;
- if (d < 0)
- return FALSE; // not inside
-
- }
-
- return TRUE;
- }
-
- /*
- * ===============
- * SampleTriangulation
- * ===============
- */
- void SampleTriangulation(vec3_t point, register struct triangulation * trian, vec3_t color)
- {
- struct triangle *t;
- struct triedge *e;
- vec_t d, best;
- struct patch *p0, *p1;
- vec3_t v1, v2;
- int i, j;
-
- if (trian->numpoints == 0) {
- VectorClear(color);
- return;
- }
- if (trian->numpoints == 1) {
- VectorCopy(trian->points[0]->totallight, color);
- return;
- }
-
- // search for triangles
- for (t = trian->tris, j = 0; j < trian->numtris; t++, j++) {
- if (!PointInTriangle(point, t))
- continue;
-
- // this is it
- LerpTriangle(trian, t, point, color);
- return;
- }
-
- // search for exterior edge
- for (e = trian->edges, j = 0; j < trian->numedges; e++, j++) {
- if (e->tri)
- continue; // not an exterior edge
-
- d = DotProduct(point, e->normal) - e->dist;
- if (d < 0)
- continue; // not in front of edge
-
- p0 = trian->points[e->p0];
- p1 = trian->points[e->p1];
-
- VectorSubtract(p1->origin, p0->origin, v1);
- VectorNormalize(v1);
- VectorSubtract(point, p0->origin, v2);
- d = DotProduct(v2, v1);
- if (d < 0)
- continue;
- if (d > 1)
- continue;
- for (i = 0; i < 3; i++)
- color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]);
- return;
- }
-
- // search for nearest point
- best = 99999;
- p1 = NULL;
- for (j = 0; j < trian->numpoints; j++) {
- p0 = trian->points[j];
- VectorSubtract(point, p0->origin, v1);
- d = VectorLength(v1);
- if (d < best) {
- best = d;
- p1 = p0;
- }
- }
-
- if (!p1)
- Error("SampleTriangulation: no points");
-
- VectorCopy(p1->totallight, color);
- }
-
- /*
- * =============
- * GatherSampleLight
- *
- * Lightscale is the normalizer for multisampling
- * =============
- */
- void GatherSampleLight(__memBase, vec3_t pos, vec3_t normal,
- register float **styletable, register int offset, register int mapsize, register float lightscale)
- {
- int i;
- struct directlight *l;
- unsigned char pvs[(MAX_MAP_LEAFS + 7) / 8];
- vec3_t delta;
- float dot, dot2;
- float dist;
- float scale = 1.0;
- float *dest;
-
- // get the PVS for the pos to limit the number of checks
- if (!PvsForOrigin(bspMem, pos, pvs)) {
- return;
- }
-
- for (i = 0; i < bspMem->numleafs; i++) {
- if ((pvs[i >> 3] & (1 << (i & 7)))) {
- for (l = directlights[i]; l; l = l->next) {
- VectorSubtract(l->origin, pos, delta);
- dist = VectorNormalize(delta);
- dot = DotProduct(delta, normal);
- if (dot <= 0.001)
- continue; // behind sample surface
- switch (l->type) {
- case emit_point:
- // linear falloff
- scale = (l->intensity - dist) * dot;
- break;
-
- case emit_surface:
- dot2 = -DotProduct(delta, l->normal);
- if (dot2 <= 0.001)
- goto skipadd; // behind light surface
- scale = (l->intensity / (dist * dist)) * dot * dot2;
- break;
-
- case emit_spotlight:
- // linear falloff
- dot2 = -DotProduct(delta, l->normal);
- if (dot2 <= l->stopdot)
- goto skipadd; // outside light cone
- scale = (l->intensity - dist) * dot;
- break;
- default:
- Error("Bad l->type");
- }
-
- if (TestLine_r(0, pos, l->origin))
- continue; // occluded
- if (scale <= 0)
- continue;
-
- // if this style doesn't have a table yet, allocate one
- if (!styletable[l->style])
- styletable[l->style] = (float *)tmalloc(mapsize);
-
- dest = styletable[l->style] + offset;
- // add some light to it
- VectorMA(dest, scale * lightscale, l->color, dest);
-
- skipadd:;
- }
- }
- /** mprogress(bspMem->numleafs, i + 1); **/
- }
-
- }
-
- /*
- * =============
- * FinalLightFace
- *
- * Add the indirect lighting on top of the direct
- * lighting and save into final map format
- * =============
- */
- void FinalLightFace(__memBase, register int facenum)
- {
- struct dface_t *f;
- int i, j, k, st;
- vec3_t lb;
- struct patch *patch;
- struct triangulation *trian = 0;
- struct facelight *fl;
- float minlight;
- float max, newmax;
- unsigned char *dest;
- int pfacenum;
- vec3_t facemins, facemaxs;
-
- f = &bspMem->dfaces[facenum];
- fl = &facelights[facenum];
-
- /** added waterlit **/
- if ((bspMem->texinfo[f->texinfo].flags & TEX_SPECIAL)) { // non-lit texture
- if(bspMem->litOptions & LIGHT_WATERLIT) {
- int *textures = (int *)(bspMem->dtexdata + 4);
- struct mipmap *tex = (struct mipmap *)(bspMem->dtexdata + textures[bspMem->texinfo[f->texinfo].miptex]);
- if(!strcmp(tex->name, "sky"))
- return;
- }
- else
- return;
- }
-
- if(bspMem->lightdatasize + (fl->numstyles * (fl->numsamples * 3)) >= bspMem->max_lightdatasize)
- ExpandClusters(bspMem, LUMP_LIGHTING);
- f->lightofs = bspMem->lightdatasize;
- bspMem->lightdatasize += fl->numstyles * (fl->numsamples * 3);
-
- f->styles[0] = 0;
- f->styles[1] = f->styles[2] = f->styles[3] = 0xff;
-
- //
- // set up the triangulation
- //
- if (numbounce > 0) {
- ClearLBounds(facemins, facemaxs);
- for (i = 0; i < f->numedges; i++) {
- int ednum = bspMem->dsurfedges[f->firstedge + i];
- if (ednum >= 0)
- AddPointToBounds(bspMem->dvertexes[bspMem->dedges[ednum].v[0]].point, facemins, facemaxs);
- else
- AddPointToBounds(bspMem->dvertexes[bspMem->dedges[-ednum].v[1]].point, facemins, facemaxs);
- }
-
- trian = AllocTriangulation(&bspMem->dplanes[f->planenum]);
-
- // for all faces on the plane, add the nearby patches
- // to the triangulation
- for (pfacenum = planelinks[f->side][f->planenum];
- pfacenum; pfacenum = facelinks[pfacenum]) {
- for (patch = facepatches[pfacenum]; patch; patch = patch->next) {
- for (i = 0; i < 3; i++) {
- if (facemins[i] - patch->origin[i] > subdiv * 2)
- break;
- if (patch->origin[i] - facemaxs[i] > subdiv * 2)
- break;
- }
- if (i != 3)
- continue; // not needed for this face
- AddPointToTriangulation(patch, trian);
- }
- }
- //for (i = 0; i < trian->numpoints; i++)
- // memset(trian->edgematrix[i], 0, trian->numpoints * sizeof(trian->edgematrix[0][0]));
- TriangulatePoints(trian);
- }
-
- //
- // sample the triangulation
- //
-
- // _minlight allows models that have faces that would not be
- // illuminated to receive a mottled light pattern instead of
- // black
- minlight = FloatForKey(faceentity[facenum], "_minlight") * 128;
-
- dest = &bspMem->dlightdata[f->lightofs];
-
- if (fl->numstyles > MAXLIGHTMAPS) {
- fl->numstyles = MAXLIGHTMAPS;
- eprintf("face with too many lightstyles: (%g %g %g)\n",
- facepatches[facenum]->origin[0],
- facepatches[facenum]->origin[1],
- facepatches[facenum]->origin[2]);
- }
-
- for (st = 0; st < fl->numstyles; st++) {
- f->styles[st] = fl->stylenums[st];
- for (j = 0; j < fl->numsamples; j++) {
- VectorCopy((fl->samples[st] + j * 3), lb);
- if (numbounce > 0 && st == 0) {
- vec3_t add;
-
- SampleTriangulation(fl->origins + j * 3, trian, add);
- VectorAdd(lb, add, lb);
- }
- // add an ambient term if desired
- lb[0] += ambient;
- lb[1] += ambient;
- lb[2] += ambient;
-
- VectorScale(lb, lightscale, lb);
-
- // we need to clamp without allowing hue to change
- for (k = 0; k < 3; k++)
- if (lb[k] < 1)
- lb[k] = 1;
- max = lb[0];
- if (lb[1] > max) max = lb[1];
- if (lb[2] > max) max = lb[2];
- newmax = max;
- if (newmax < 0)
- newmax = 0; // roundoff problems
-
- if (newmax < minlight) {
- newmax = minlight + (rand() % 48);
- }
- if (newmax > maxlight)
- newmax = maxlight;
-
- for (k = 0; k < 3; k++) {
- *dest++ = lb[k] * newmax / max;
- }
- }
- }
-
- if (numbounce > 0)
- FreeTriangulation(trian);
- }
-
- /*
- * =============
- * RadFace
- * =============
- */
- float sampleofs[5][2] =
- {
- {0, 0},
- {-0.25, -0.25},
- {0.25, -0.25},
- {0.25, 0.25},
- {-0.25, 0.25}};
-
- void RadFace(__memBase, register int facenum)
- {
- struct dface_t *f;
- struct lightinfo l[5];
- float *styletable[MAX_LSTYLES];
- int i, j;
- float *spot;
- struct patch *patch;
- int numsamples;
- int tablesize;
- struct facelight *fl;
-
- f = &bspMem->dfaces[facenum];
-
- /** added waterlit **/
- if ((bspMem->texinfo[f->texinfo].flags & TEX_SPECIAL)) { // non-lit texture
- if(bspMem->litOptions & LIGHT_WATERLIT) {
- int *textures = (int *)(bspMem->dtexdata + 4);
- struct mipmap *tex = (struct mipmap *)(bspMem->dtexdata + textures[bspMem->texinfo[f->texinfo].miptex]);
- if(!strcmp(tex->name, "sky"))
- return;
- }
- else
- return;
- }
- memset(styletable, 0, sizeof(styletable));
-
- if (bspMem->litOptions & LIGHT_EXTRA)
- numsamples = 5;
- else
- numsamples = 1;
-
- for (i = 0; i < numsamples; i++) {
- memset(&l[i], 0, sizeof(l[i]));
- l[i].surfnum = facenum;
- l[i].face = f;
- VectorCopy(bspMem->dplanes[f->planenum].normal, l[i].facenormal);
- l[i].facedist = bspMem->dplanes[f->planenum].dist;
- if (f->side) {
- VectorNegate(l[i].facenormal);
- l[i].facedist = -l[i].facedist;
- }
-
- // get the origin offset for rotating bmodels
- VectorCopy(faceoffset[facenum], l[i].modelorg);
-
- CalcFaceVectors(bspMem, &l[i]);
- CalcFaceExtentsII(bspMem, &l[i]);
- CalcPoints(bspMem, &l[i], sampleofs[i][0], sampleofs[i][1]);
- }
-
- tablesize = l[0].numsurfpt * sizeof(vec3_t);
- styletable[0] = (float *)tmalloc(tablesize);
-
- fl = &facelights[facenum];
- fl->numsamples = l[0].numsurfpt;
- fl->origins = (float *)tmalloc(tablesize);
- memcpy(fl->origins, l[0].surfpt, tablesize);
-
- for (i = 0; i < l[0].numsurfpt; i++) {
- for (j = 0; j < numsamples; j++)
- GatherSampleLight(bspMem, l[j].surfpt[i], l[0].facenormal, styletable, i * 3, tablesize, 1.0 / numsamples);
- // contribute the sample to one or more patches
- AddSampleToPatch(l[0].surfpt[i], styletable[0] + i * 3, facenum);
- }
-
- // average up the direct light on each patch for radiosity
- for (patch = facepatches[facenum]; patch; patch = patch->next) {
- if (patch->samples)
- VectorScale(patch->samplelight, 1.0 / patch->samples, patch->samplelight);
- }
-
- for (i = 0; i < MAX_LSTYLES; i++) {
- if (!styletable[i])
- continue;
- if (fl->numstyles == MAX_STYLES)
- break;
- fl->samples[fl->numstyles] = styletable[i];
- fl->stylenums[fl->numstyles] = i;
- fl->numstyles++;
- }
-
- // the light from DIRECT_LIGHTS is sent out, but the
- // texture itself should still be full bright
- if (facepatches[facenum]->baselight[0] >= DIRECT_LIGHT ||
- facepatches[facenum]->baselight[1] >= DIRECT_LIGHT ||
- facepatches[facenum]->baselight[2] >= DIRECT_LIGHT) {
- spot = fl->samples[0];
- for (i = 0; i < l[0].numsurfpt; i++, spot += 3)
- VectorAdd(spot, facepatches[facenum]->baselight, spot);
- }
- }
-
- /*
- * =============
- * RadWorld
- * =============
- */
- void RadWorld(__memBase) {
- int back, i;
-
- mprintf("CalcTR\n");
- CalcTextureReflectivity(bspMem);
- mprintf("MakeMB\n");
- MakeBackPlanes(bspMem);
- mprintf("MakeP\n");
- MakeParents(bspMem, 0, -1);
- // turn each face into a single patch
- mprintf("MakePa\n");
- MakePatches(bspMem);
- // subdivide patches to a maximum dimension
- mprintf("SubD\n");
- SubdividePatches(bspMem);
- mprintf("%5i patches\n", numpatches);
- // create directlights out of patches and lights
- mprintf("CreateDL\n");
- CreateDirectLights(bspMem);
- mprintf("%5i patches\n", numpatches);
- back = numpatches;
- for (i = 0; i < bspMem->numfaces; i++, bspfileface++) {
- RadFace(bspMem, i);
- mprogress(bspMem->numfaces, i + 1);
- }
- mprintf("%5i patches: %d\n", numpatches);
- numpatches = back;
- mprintf("%5i patches: %d\n", numpatches);
- if (numbounce > 0) {
- // build transfer lists
- mprintf("MakeTr\n");
- for (i = 0; i < numpatches; i++)
- MakeTransfers(bspMem, i);
-
- mprintf("transfer lists: %g megs\n",(float)total_transfer * sizeof(struct transfer) / (1024 * 1024));
- // spread light around
- mprintf("Bounce\n");
- BounceLight();
- mprintf("FreeTr\n");
- FreeTransfers();
- mprintf("CheckP\n");
- CheckPatches();
- }
- // blend bounced light into direct light and save
- mprintf("PairEd\n");
- PairEdges(bspMem);
- mprintf("LinkPl\n");
- LinkPlaneFaces(bspMem);
- bspMem->lightdatasize = 0;
- for (i = 0; i < bspMem->numfaces; i++) {
- FinalLightFace(bspMem, i);
- mprogress(bspMem->numfaces, i + 1);
- }
- }
-
-